#pragma once
#include <iostream>
#include <string>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
using namespace std;



enum {
    SocketError = 0,
    BindError,
    ListenError,
    AcceptError,
    ConnectError
};
const int default_sockfd = -1;
const int default_backlog = 5;



class Socket {
public :
    Socket() {

    }
    // 创建套接字
    virtual void CreateSocketOrDie() = 0;
    // 绑定套接字
    virtual void BindSocketOrDie(uint16_t port) = 0;
    // 监听套接字
    virtual void ListenSocketOrDie(int backlog) = 0;
    // 获取连接
    virtual Socket* AcceptSocket(string* peerip, uint16_t* peerport) =  0;
    // 建立连接
    virtual bool ConnectServer(string& serverip, uint16_t serverport) = 0;
    // 获取套接字文件描述符
    virtual int GetSockFd() = 0;
    virtual void SetSockFd(int sockfd) = 0;
    virtual void CloseSockFd() = 0;
    virtual bool Recv(string* buffer, int elemsize) = 0;
    virtual bool Send(string& send_string) = 0;

    virtual ~Socket() {}

public :
    // 创建一个监听套接字(给服务端用的)
    void BuildListenSocketMethod(uint16_t port, int backlog) {
        CreateSocketOrDie();
        BindSocketOrDie(port);
        ListenSocketOrDie(backlog);
    }

    // 创建一个链接套接字(给客户端用的)
    bool BuildConnectSocketMethod(string& serverip, uint16_t serverport) {
        CreateSocketOrDie();
        // 不需要绑定，客户端会自动绑定
        return ConnectServer(serverip, serverport);
    }
    void BuildNormalSocketMethod(int sockfd) {
        SetSockFd(sockfd);
        
    }
private :
};


class TcpSocket : public Socket {
public :
    TcpSocket(int sockfd = default_sockfd) 
        :_sockfd(sockfd)
    {}
    // 创建套接字
    void CreateSocketOrDie() override {
        _sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_sockfd < 0) {
            cerr << "create socket error, error code: " << errno << ", error string: " << strerror(errno) << endl;
            exit(SocketError);
        }
        cout << "create socket success sockfd: " << _sockfd << endl;
    }
    // 绑定套接字
    void BindSocketOrDie(uint16_t port) override {
        struct sockaddr_in local;
        memset(&local, 0, sizeof local);
        local.sin_family = AF_INET;
        local.sin_port = htons(port);
        local.sin_addr.s_addr = INADDR_ANY;
        int n = bind(_sockfd, (struct sockaddr*)&local, sizeof local);
        if (n < 0) {
            cerr << "bind socket error, error code: " << errno << ", error string: " << strerror(errno) << endl;
            exit(BindError);            
        }
        cout << "bind socket success!" << endl;
    }
    // 监听套接字
    void ListenSocketOrDie(int backlog) override {
        int n = listen(_sockfd, backlog);
        if (n < 0) {
            cerr << "listen socket error, error code: " << errno << ", error string: " << strerror(errno) << endl;
            exit(ListenError);              
        }
        cout << "listen socket sucess!" << endl;
    }
    // 获取连接
    Socket* AcceptSocket(string* peerip, uint16_t* peerport) override {
        struct sockaddr_in peer;
        memset(&peer, 0, sizeof peer);
        socklen_t len = sizeof peer;
        
        int newsockfd = accept(_sockfd, (struct sockaddr*)&peer, &len);
        if (newsockfd < 0) {
            cerr << "accept error, error code: " << errno << ", error string: " << strerror(errno) << endl;
            exit(AcceptError);                
        }
        cout << "accept success newsockfd: " << newsockfd << endl;
        *peerip = inet_ntoa(peer.sin_addr);
        *peerport = htons(peer.sin_port);
        Socket* s = new TcpSocket(newsockfd);
        return s;
    }
    // 建立连接
    bool ConnectServer(string& serverip, uint16_t serverport) override {
        struct sockaddr_in server;
        memset(&server, 0, sizeof server);
        server.sin_family = AF_INET;
        server.sin_port = htons(serverport);
        server.sin_addr.s_addr = inet_addr(serverip.c_str());
        int n = connect(_sockfd, (struct sockaddr*)&server, sizeof server);
        if (n < 0) {
            cerr << "connect error, error code: " << errno << ", error string: " << strerror(errno) << endl;
            return false;   
        }
        cout << "connect success!" << endl;
        return true;
    }
    // 获取套接字文件描述符
    int GetSockFd() override {
        return _sockfd;
    }
    void SetSockFd(int sockfd) override {
        _sockfd = sockfd;
    }
    void CloseSockFd() override {
        close(_sockfd);
    }
    bool Recv(string* buffer, int elemsize) override {
        char inbuffer[elemsize];
        int n = recv(_sockfd, inbuffer, elemsize - 1, 0);
        if (n > 0) {
            inbuffer[n] = '\0';
            *buffer += inbuffer;
            return true;
        } else if (n == 0) {
            cerr << "peer close" << endl;
            return false;
        } else {
            cerr << "recv error, error code: " << errno << ", error string: " << strerror(errno) << endl;
            return false;
        }
    }
    bool Send(string& send_string) override {
        int n = send(_sockfd, send_string.c_str(), send_string.size(), 0);
        if (n < 0) {
            cerr << "send error, error code: " << errno << ", error string: " << strerror(errno) << endl;
            return false;
        }
        return true;
    }
    ~TcpSocket() {

    }
private :
    int _sockfd;
};